﻿using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using DoNet.Utils;
using DoNet.TenPay;
using log4net;

namespace DoNet.Web.Controllers
{
    public class NotifyController : Controller
    {
        private readonly IConfiguration config;
        private IMemoryCache cache;

        public NotifyController(IConfiguration config, IMemoryCache cache)
        {
            this.config = config;
            this.cache = cache;
        }
        private readonly ILog _log = LogManager.GetLogger(Startup.LogRepository.Name, typeof(HomeController));

        /// <summary>
        /// 支付/退款结果通知 GET: Notify
        /// </summary>
        /// <param name="type">结果通知类型 支付结果通知（Result）/退款结果通知（Refund）</param>
        /// <returns></returns>
        public ActionResult Index(string type)
        {
            //返回数据
            string result = "";

            /* 这里信息读取配置文件中的数据 */
            int payMode = Convert.ToInt32(config["TenPay:payMode"]); // 微信支付商户类型：0 普通商户 1 服务商
            string version = config["TenPay:Version"]; // 微信支付版本 V2 V3
            string merchantId = config["TenPay:MerchantId"]; // 微信支付商户号（服务商 ）
            /* 这里信息读取配置文件中的数据 */

            //应答主体（response Body）
            string bodyData = GetBodyData();
            if (!string.IsNullOrWhiteSpace(bodyData))
            {
                bool isSuccess = false;

                //微信支付 V2/V3版本
                if (version == "V3")
                {
                    /* 这里信息读取配置文件中的数据 */
                    string apiKeyV3 = config["TenPay:ApiKeyV3"];

                    string Serial = Request.Headers["Wechatpay-Serial"].FirstOrDefault();
                    string Signature = Request.Headers["Wechatpay-Signature"].FirstOrDefault();
                    string Timestamp = Request.Headers["Wechatpay-Timestamp"].FirstOrDefault();
                    string Nonce = Request.Headers["Wechatpay-Nonce"].FirstOrDefault();

                    string signSourceString = Timestamp + "\n" + Nonce + "\n" + bodyData + "\n";

                    var isVerifySign = SignatureV3.VerifySign(Signature, signSourceString, Serial, merchantId, apiKeyV3);
                    if (isVerifySign)
                    {
                        var resultNotify = JsonUtil.JsonToT<NotifyV3Model>(bodyData);
                        if (resultNotify != null)
                        {
                            if (resultNotify.event_type == "TRANSACTION.SUCCESS")
                            {
                                var resource = resultNotify.resource;
                                string nonce = resource.nonce;
                                string ciphertext = resource.ciphertext;
                                string associated_data = resource.associated_data;

                                //异常以及解决方案： 错误：mac check in GCM failed   这个异常不是代码错误，是解密失败。 
                                //特别特别要检查商户平台上设置的APIv3密钥是否正确。检查解密函数中参数是否正确。
                                var decryptResult = AesGcmUtil.Decrypt(ciphertext, apiKeyV3, associated_data);
                                if (!string.IsNullOrWhiteSpace(decryptResult))
                                {
                                    //支付结果通知
                                    if (type == "Result")
                                    {
                                        var orderModel = WechatResultV3(merchantId, payMode, decryptResult);
                                        if (orderModel != null)
                                        {
                                            isSuccess = true; //支付成功 付款成功处理逻辑

                                            //微信订单号
                                            string transaction_id = orderModel.transaction_id;
                                            //商户订单号
                                            string out_trade_no = orderModel.out_trade_no;

                                            //交易状态，枚举值：SUCCESS：支付成功 REFUND：转入退款 NOTPAY：未支付 CLOSED：已关闭 REVOKED：已撤销（付款码支付） USERPAYING：用户支付中（付款码支付） PAYERROR：支付失败(其他原因，如银行返回失败)
                                            string trade_state = orderModel.trade_state;

                                            //用户是否关注公众账号，Y-关注，N-未关注
                                            //string is_subscribe = "";
                                            //Log.Info("ResultNotify", "is_subscribe : " + is_subscribe);
                                            //交易类型
                                            string trade_type = orderModel.trade_type;
                                            //Log.Info("ResultNotify", "trade_type : " + trade_type);
                                            //付款银行
                                            string bank_type = orderModel.bank_type;
                                            //Log.Info("ResultNotify", "bank_type : " + bank_type);
                                            //订单总金额，单位为分
                                            decimal total_fee = Convert.ToDecimal(orderModel.amount.total * 0.01);
                                            //Log.Info("ResultNotify", "total_fee : " + total_fee);
                                            //现金支付金额，单位为分 
                                            decimal cash_fee = Convert.ToDecimal(orderModel.amount.payer_total * 0.01);
                                            //Log.Info("ResultNotify", "cash_fee: " + cash_fee);
                                            //支付完成时间	time_end
                                            var success_time = orderModel.success_time;
                                            //Log.Info("ResultNotify", "time_end: " + time_end);
                                            string pay_date = Convert.ToDateTime(success_time).ToString("yyyy-MM-dd HH:mm:ss");

                                        }
                                    }
                                    else if (type == "Refund") //申请退款结果通知
                                    {
                                        var refundModel = WechatRefundV3(merchantId, payMode, decryptResult);
                                        if (refundModel != null)
                                        {
                                            isSuccess = true; //退款成功

                                            //退款成功处理逻辑

                                            //微信订单号
                                            string transaction_id = refundModel.transaction_id;
                                            //商户订单号
                                            string out_trade_no = refundModel.out_trade_no;
                                            //微信退款单号
                                            string refund_id = refundModel.refund_id;

                                            //商户退款单号
                                            string out_refund_no = refundModel.out_refund_no;
                                            //订单金额
                                            decimal total_fee = Convert.ToDecimal(refundModel.amount.total * 0.01);
                                            //用户退款金额 payer_refund 
                                            decimal settlement_total_fee = Convert.ToDecimal(refundModel.amount.payer_refund * 0.01);
                                            //申请退款金额 refund_fee
                                            decimal refund_fee = Convert.ToDecimal(refundModel.amount.refund * 0.01);
                                            //退款成功时间 success_time 
                                            string success_time = "";
                                            if (!string.IsNullOrEmpty(refundModel.success_time))
                                            {
                                                success_time = Convert.ToDateTime(refundModel.success_time).ToString("yyyy-MM-dd HH:mm:ss");
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，通知的类型【" + resultNotify.event_type + "】，返回结果解密失败！");
                                }
                            }
                            else
                            {
                                _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，通知的类型【" + resultNotify.event_type + "】！");
                            }
                        }
                        else
                        {
                            _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，通知结果为空！");
                         }
                    }
                    else
                    {
                        _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，验证签名失败！");
                    }

                    object jsonData = null;
                    if (isSuccess)
                    {
                        jsonData = new
                        {
                            code = "SUCCESS",
                            message = "成功"
                        };
                    }
                    else
                    {
                        jsonData = new
                        {
                            code = "FAIL",
                            message = "失败"
                        };
                    }
                    result = JsonUtil.ObjectToJson(jsonData);
                }
                else if (version == "V2")
                {
                    Hashtable resultHashtable = null;

                    string sign_type = SignatureV2.SIGN_TYPE_HMAC_SHA256;
                    /* 这里信息读取配置文件中的数据 */
                    string apiKeyV2 = config["TenPay:ApiKeyV2"];

                    //支付结果通知
                    if (type == "Result")
                    {
                        var orderModel = WechatResultV2(merchantId, payMode, apiKeyV2, bodyData, sign_type);
                        if (orderModel != null)
                        {
                            isSuccess = true; //支付成功

                            //付款成功处理逻辑
                            //商户订单号
                            string out_trade_no = orderModel.out_trade_no;
                            //Log.Info("ResultNotify", "out_trade_no : " + out_trade_no);
                            //用户是否关注公众账号，Y-关注，N-未关注
                            string is_subscribe = orderModel.is_subscribe;
                            //Log.Info("ResultNotify", "is_subscribe : " + is_subscribe);
                            //交易类型
                            string trade_type = orderModel.trade_type;
                            //Log.Info("ResultNotify", "trade_type : " + trade_type);
                            //付款银行
                            string bank_type = orderModel.bank_type;
                            //Log.Info("ResultNotify", "bank_type : " + bank_type);
                            //订单总金额，单位为分
                            decimal total_fee = Convert.ToDecimal(orderModel.total_fee * 0.01);
                            //Log.Info("ResultNotify", "total_fee : " + total_fee);
                            //现金支付金额，单位为分 
                            decimal cash_fee = Convert.ToDecimal(orderModel.cash_fee * 0.01);
                            //Log.Info("ResultNotify", "cash_fee: " + cash_fee);
                            //支付完成时间	time_end
                            string time_end = orderModel.time_end;
                            //Log.Info("ResultNotify", "time_end: " + time_end);
                        }
                    }
                    else if (type == "Refund") //申请退款结果通知
                    {
                        var refundModel = WechatRefundV2(merchantId, payMode, apiKeyV2, bodyData, sign_type);
                        if (refundModel != null)
                        {
                            isSuccess = true; //退款成功

                            //退款成功处理逻辑
                            //服务商/商户的APPID
                            string appid = refundModel.appid;
                            //退款商户号
                            string mch_id = refundModel.mch_id;
                            //特约商户公众账号ID
                            string sub_appid = ((SpRefundBaseV2)refundModel).sub_appid;
                            //特约商户商户号
                            string sub_mch_id = ((SpRefundBaseV2)refundModel).sub_mch_id;
                            //随机字符串
                            string nonce_str = refundModel.nonce_str;
                            //微信订单号
                            string transaction_id = refundModel.transaction_id;
                            //商户订单号
                            string out_trade_no = refundModel.out_trade_no;
                            //微信退款单号
                            string refund_id = refundModel.refund_id;
                            //商户退款单号
                            string out_refund_no = refundModel.out_refund_no;
                            //订单金额
                            decimal total_fee = Convert.ToDecimal(refundModel.total_fee * 0.01);
                            //应结订单金额 settlement_total_fee 否
                            decimal settlement_total_fee = Convert.ToDecimal(refundModel.settlement_total_fee * 0.01);
                            //申请退款金额 refund_fee
                            decimal refund_fee = Convert.ToDecimal(refundModel.refund_fee * 0.01);
                            //退款成功时间 success_time 否
                            string success_time = refundModel.refund_success_time;

                        }
                    }

                    if (isSuccess)
                    {
                        //支付成功返回信息
                        resultHashtable.Add("return_code", "SUCCESS");
                        resultHashtable.Add("return_msg", "OK");
                    }
                    else
                    {
                        resultHashtable.Add("return_code", "FAIL");
                        resultHashtable.Add("return_msg", "失败！");
                    }
                    result = SignatureV2.ToXml(resultHashtable);
                }
            }
            return Content(result);
        }

        /// <summary>
        /// 微信支付结果V3
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="payMode">商户类型 0 普通商户 1 服务商（微信支付）</param>
        /// <param name="decryptResult">支付结果中解密的支付订单信息</param>
        /// <returns>IQueryOrderBase : SpQueryOrderReseult/QueryOrderReseult </returns>
        public IQueryOrderBase WechatResultV3(string merchantId, int payMode, string decryptResult)
        {
            IQueryOrderBase reseult = null;
            IQueryOrderBase decryptModel = null;
            //解密后的结果就是订单查询的结果
            if (payMode == 1)
            {
                decryptModel = JsonUtil.JsonToT<SpQueryOrderReseult>(decryptResult);
            }
            else if (payMode == 0)
            {
                decryptModel = JsonUtil.JsonToT<QueryOrderReseult>(decryptResult);
            }
            if (decryptModel != null)
            {
                //微信订单号
                string transaction_id = decryptModel.transaction_id;
                //商户订单号
                string out_trade_no = decryptModel.out_trade_no;

                //交易状态，枚举值：SUCCESS：支付成功 REFUND：转入退款 NOTPAY：未支付 CLOSED：已关闭 REVOKED：已撤销（付款码支付） USERPAYING：用户支付中（付款码支付） PAYERROR：支付失败(其他原因，如银行返回失败)
                var trade_state = decryptModel.trade_state;
                if (trade_state == "SUCCESS")
                {
                    reseult = decryptModel;
                }
                else
                {
                    _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，微信订单号【" + transaction_id + "】，交易状态【" + trade_state + "】！");
                }
            }
            else
            {
                _log.Error("微信支付【V3版】，商户号【" + merchantId + "】【支付】，解密后的结果为空！");
            }
            return reseult;
        }
        /// <summary>
        /// 微信退款结果V3
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="payMode">商户类型 0 普通商户 1 服务商（微信支付）</param>
        /// <param name="decryptResult">支付结果中解密的支付订单信息</param>
        /// <returns>IRefundBase : RefundV3ModelSp/RefundV3Model </returns>
        public IRefundBase WechatRefundV3(string merchantId, int payMode, string decryptResult)
        {
            IRefundBase reseult = null;
            IRefundBase decryptModel = null;
            //解密后的结果
            if (payMode == 1)
            {
                decryptModel = JsonUtil.JsonToT<RefundV3ModelSp>(decryptResult);
            }
            else if (payMode == 0)
            {
                decryptModel = JsonUtil.JsonToT<RefundV3Model>(decryptResult);
            }
            if (decryptModel != null)
            {
                //微信订单号
                string transaction_id = decryptModel.transaction_id;
                //商户订单号
                string out_trade_no = decryptModel.out_trade_no;
                //微信退款单号
                string refund_id = decryptModel.refund_id;

                //退款状态 退款状态 refund_status SUCCESS - 退款成功 CHANGE - 退款异常 REFUNDCLOSE—退款关闭
                string refund_status = decryptModel.refund_status;
                if (refund_status == "SUCCESS")
                {
                    reseult = decryptModel;
                }
                else
                {
                    _log.Error("微信支付【V3版】，商户号【" + merchantId + "】，微信订单号【" + transaction_id + "】，微信退款单号【" + refund_id + "】，退款状态【" + refund_status + "】！");
                }
            }
            else
            {
                _log.Error("微信支付【V3版】，商户号【" + merchantId + "】【退款】，解密后的结果为空！");
            }
            return reseult;
        }
        /// <summary>
        /// 微信支付结果V2
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="payMode">商户类型 0 普通商户 1 服务商（微信支付）</param>
        /// <param name="apiKeyV2">微信支付V2版本API KEY</param>
        /// <param name="bodyData">支付结果</param>
        /// <param name="sign_type">签名类型</param>
        /// <returns>INotifyResultBase : ResponseNotifyResultSp/ResponseNotifyResult </returns>
        public INotifyResultBase WechatResultV2(string merchantId, int payMode, string apiKeyV2, string bodyData, string sign_type)
        {
            INotifyResultBase reseult = null;
            INotifyResultBase notifyResult = null;
            if (payMode == 1)
            {
                notifyResult = JsonUtil.JsonToT<ResponseNotifyResultSp>(bodyData);
            }
            else if (payMode == 0)
            {
                notifyResult = JsonUtil.JsonToT<ResponseNotifyResult>(bodyData);
            }
            if (notifyResult != null)
            {
                //验证签名
                var notifyHashtable = SignatureV2.ObjectToHashtable(notifyResult);
                if (SignatureV2.CheckSign(notifyHashtable, sign_type, apiKeyV2))
                {
                    var return_code = notifyResult.return_code;
                    if (return_code == "SUCCESS")
                    {
                        //微信订单号
                        string transaction_id = notifyResult.transaction_id;
                        //检查支付结果中transaction_id是否存在
                        if (!string.IsNullOrEmpty(transaction_id))
                        {
                            string result_code = notifyResult.result_code;
                            //Log.Info("ResultNotify", "result_code: " + result_code);
                            //判断签名及结果
                            if (result_code == "SUCCESS")
                            {
                                reseult = notifyResult;
                            }
                            else
                            {
                                _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，支付失败，result_code 不等于 SUCCESS！");
                            }
                        }
                        else
                        {
                            _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，支付结果中微信订单号不存在！");
                        }
                    }
                    else
                    {
                        _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，返回状态码【" + return_code + "】，返回信息【" + notifyResult.return_msg + "】！");
                    }
                }
                else
                {
                    _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，支付结果，验证签名失败！");
                }
            }
            else
            {
                _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，支付结果为空！");
            }
            return reseult;
        }
        /// <summary>
        /// 微信退款结果V2
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="payMode">商户类型 0 普通商户 1 服务商（微信支付）</param>
        /// <param name="apiKeyV2">微信支付V2版本API KEY</param>
        /// <param name="bodyData">支付结果</param>
        /// <param name="sign_type">签名类型</param>
        /// <returns>IRefundBaseV2 ： SpRefundBaseV2/RefundBaseV2</returns>
        public IRefundBaseV2 WechatRefundV2(string merchantId, int payMode, string apiKeyV2, string bodyData, string sign_type)
        {
            IRefundBaseV2 reseult = null;

            INotifyRefundBase notifyResult = null;
            if (payMode == 1)
            {
                notifyResult = JsonUtil.JsonToT<ResponseNotifyRefundSp>(bodyData);
            }
            else if (payMode == 0)
            {
                notifyResult = JsonUtil.JsonToT<ResponseNotifyRefund>(bodyData);
            }
            if (notifyResult != null)
            {
                //验证签名
                var notifyHashtable = SignatureV2.ObjectToHashtable(notifyResult);
                if (SignatureV2.CheckSign(notifyHashtable, sign_type, apiKeyV2))
                {
                    var return_code = notifyResult.return_code;
                    if (return_code == "SUCCESS")
                    {
                        //加密信息
                        string req_info = notifyResult.req_info;
                        var refundDecode = DecodeRefundInfo(merchantId, apiKeyV2, req_info);
                        if (refundDecode != null)
                        {
                            if (payMode == 1)
                            {
                                reseult = new SpRefundBaseV2()
                                {
                                    appid = notifyResult.appid, //服务商的APPID
                                    mch_id = notifyResult.mch_id,//退款商户号
                                    sub_appid = ((ResponseNotifyRefundSp)notifyResult).sub_appid,//特约商户公众账号ID
                                    sub_mch_id = ((ResponseNotifyRefundSp)notifyResult).sub_mch_id,//特约商户商户号
                                    nonce_str = notifyResult.nonce_str,//随机字符串
                                    transaction_id = refundDecode.transaction_id,
                                    out_trade_no = refundDecode.out_trade_no,
                                    out_refund_no = refundDecode.out_refund_no,
                                    refund_id = refundDecode.refund_id,
                                    total_fee = refundDecode.total_fee,
                                    settlement_total_fee = refundDecode.settlement_total_fee,
                                    refund_fee = refundDecode.refund_fee,
                                    settlement_refund_fee = refundDecode.settlement_refund_fee,
                                    refund_status = refundDecode.refund_status,
                                    refund_success_time = refundDecode.refund_success_time,
                                    refund_recv_accout = refundDecode.refund_recv_accout,
                                    refund_account = refundDecode.refund_account,
                                    refund_request_source = refundDecode.refund_request_source,
                                    cash_refund_fee = refundDecode.cash_refund_fee
                                };
                            }
                            else if (payMode == 0)
                            {
                                reseult = new RefundBaseV2()
                                {
                                    appid = notifyResult.appid, //商户公众账号/应用ID
                                    mch_id = notifyResult.mch_id,//退款商户号
                                    nonce_str = notifyResult.nonce_str,//随机字符串
                                    transaction_id = refundDecode.transaction_id,
                                    out_trade_no = refundDecode.out_trade_no,
                                    out_refund_no = refundDecode.out_refund_no,
                                    refund_id = refundDecode.refund_id,
                                    total_fee = refundDecode.total_fee,
                                    settlement_total_fee = refundDecode.settlement_total_fee,
                                    refund_fee = refundDecode.refund_fee,
                                    settlement_refund_fee = refundDecode.settlement_refund_fee,
                                    refund_status = refundDecode.refund_status,
                                    refund_success_time = refundDecode.refund_success_time,
                                    refund_recv_accout = refundDecode.refund_recv_accout,
                                    refund_account = refundDecode.refund_account,
                                    refund_request_source = refundDecode.refund_request_source,
                                    cash_refund_fee = refundDecode.cash_refund_fee
                                };
                            }
                        }
                    }
                    else
                    {
                        _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，退款结果中，返回状态码【return_code】【" + return_code + "】，返回信息【return_msg】【" + notifyResult.return_msg + "】！");
                    }
                }
                else
                {
                    _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，退款结果，验证签名失败！");
                }
            }
            else
            {
                _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，退款结果为空！");
            }
            return reseult;
        }
        /// <summary>
        /// 微信V2退款结果解密
        /// </summary>
        /// <returns></returns>
        public ResponseNotifyRefundDecode DecodeRefundInfo(string merchantId, string apiKeyV2, string req_info)
        {
            ResponseNotifyRefundDecode result = null;
            if (!string.IsNullOrEmpty(req_info))
            {
                var keyMd5 = SignHelper.CalMd5(apiKeyV2).ToLower();
                var req_info_Decode = SignatureV2.DecodeAES256ECB(req_info, keyMd5);
                if (!string.IsNullOrEmpty(req_info_Decode))
                {
                    var req_info_result = JsonUtil.JsonToT<ResponseNotifyRefundDecode>(req_info_Decode);
                    if (req_info_result != null)
                    {
                        //微信订单号
                        string transaction_id = req_info_result.transaction_id;
                        //商户订单号
                        string out_trade_no = req_info_result.out_trade_no;
                        //微信退款单号
                        string refund_id = req_info_result.refund_id;

                        //退款状态 退款状态 refund_status SUCCESS - 退款成功 CHANGE - 退款异常 REFUNDCLOSE—退款关闭
                        string refund_status = req_info_result.refund_status;
                        if (refund_status == "SUCCESS")
                        {
                            result = req_info_result;
                        }
                        else
                        {
                            _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，微信退款单号【" + refund_id + "】，退款状态【" + refund_status + "】！");
                        }
                    }
                }
                else
                {
                    _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，退款结果中，加密信息解密失败！");
                }
            }
            else
            {
                _log.Error("微信支付【V2版】，商户号【" + merchantId + "】，退款结果中req_info不存在！");
            }
            return result;
        }

        /// <summary>
        /// 获取通知回调过来的数据
        /// </summary>
        /// <returns></returns>
        public string GetBodyData()
        {
            string bodyData = string.Empty;
            using (Stream stream = Request.Body)
            {
                stream.Position = 0;
                using (var streamReader = new StreamReader(stream, Encoding.UTF8))
                {
                    bodyData = streamReader.ReadToEndAsync().Result;
                    stream.Position = 0;
                }
            }
            return bodyData;
        }
    }
}
